Unity3D, VSCode, OS X and ‘The reference assemblies for framework “.NETFramework,Version=v3.5” were not found’ error

This happened to me in this environment:
* OS X 10.10.5
* Unity 5.6.0b7
* VSCode 1.9.1 with C# extension 1.7.0

I had this error inside of VSCode when I opened up a Unity project:

The reference assemblies for framework “.NETFramework,Version=v3.5” were not found. To resolve this, install the SDK or Targeting Pack for this framework version or retarget your application to a version of the framework for which you have the SDK or Targeting Pack installed. Note that assemblies will be resolved from the Global Assembly Cache (GAC) and will be used in place of reference assemblies. Therefore your assembly may not be correctly targeted for the framework you intend.

Also, VSCode’s code completion did not work. Even with the right version of OpenSSL:

$openssl version
OpenSSL 1.0.2k  26 Jan 2017

and dotnet:

$dotnet

Microsoft .NET Core Shared Framework Host

  Version  : 1.1.0
  Build    : 928f77c4bc3f49d892459992fb6e1d5542cb5e86

I found this fix here:
https://github.com/OmniSharp/omnisharp-vscode/issues/1004

I had to install mono with

brew install mono

with that, I could run mono

$mono --version
Mono JIT compiler version 4.6.2 (Stable 4.6.2.16/ac9e222 Sun Jan  8 00:00:20 GMT 2017)
Copyright (C) 2002-2014 Novell, Inc, Xamarin Inc and Contributors. www.mono-project.com
    TLS:           normal
    SIGSEGV:       altstack
    Notification:  kqueue
    Architecture:  amd64
    Disabled:      none
    Misc:          softdebug
    LLVM:          supported, not enabled.
    GC:            sgen

just to prove it is installed. VSCode’s OmniSharp found acknowledged it found in its own output window while starting up and loading the project:

Discovered Mono file path: /usr/local/bin/mono
Resolved symbolic link for Mono file path: /usr/local/Cellar/mono/4.6.2.16/bin/mono-sgen

Then my code completion worked. Yay!

Ember.js night with Full Stack Toronto

I think the location is a secret.

Jasna gave a live-coded demo of using Ember to make requests to a RESTful API to do CRUD operations and display the results. Ember is an opinionated, batteries-included framework. It has more opinions than Angular when comes to data modelling.

Vikram talked about his experience working with Ember.js at LinkedIn. I wrote down some words:

  • JSON API is a specification for JSON responses from servers. It exists to stop people from arguing about how to format arrays and objects and data in HTTP responses. Just stick to the specification and you’ll probably be OK.
  • Ember Engines are little composable chunks of applications that come together to form bigger applications. An Ember Engine has a lot in common in an Ember Application, but it can’t run on its own or control a router.
  • Glimmer 2 is a new faster renderer for Ember Applications
  • LinkedIn had to figure out server-side rendering for Ember for some pages that had to be visible to search engines & crawlers. Ember now supports SSR with FastBoot.

Ember.js – Feb FSTO Meetup

Wednesday, Feb 8, 2017, 6:00 PM

18 People Went

Check out this Meetup →

February 2016 Toronto Web Performance Group meetup

We met at Shopify‘s office.

David Bokan from the Google Chrome team in Waterloo talked about scrolling performance in Google Chrome

slides

David Barreto talked about optimizing Angular 2 apps for download size & performance

There nice charts in his slides showing the effects of AoT compilation, different chunk loading strategies, and more

The Shiny and New in Chrome/Blink Performance + Big Performance in Angular 2

Monday, Feb 6, 2017, 6:30 PM

Shopify Toronto
80 Spadina Ave. 4th Floor Toronto, ON

39 Members Went

Welcome to 2017.We hope all had a wonderful holiday break. I know that we did. And we’re more than delighted to get things started in 2017. As always, we’re doing our best to bring you all corners of the web performance ecosystems in the form of fascinating talks.One item being tabled was the idea of having more presentations from browser vendor…

Check out this Meetup →

Host your own Git LFS with node-lfs-s3

Want to use Git LFS without a Git-as-a-Service provider like GitHub or BitBucket?

Stuff you will need

  • AWS S3 to store files at a low cost
  • node-lfs-s3 to communicate between Git and S3. This can run on your own machine or in the cloud.
  • Git LFS installed in your development environment or a server you control and available in the system’s PATH. I’m using git-lfs/1.4.4 (GitHub; darwin amd64; go 1.7.3; git cbf91a9) with git version 2.5.4 (Apple Git-61) on OS X, and something else on Windows 10.
  • GitHub for Windows comes with its own Git LFS executable which may override the version you install on your own.

Things to configure

Your Git repository needs a file called .lfsconfig which points it at the Git LFS server. Here’s an example:

[lfs]
url = "http://host:port/github-account-name/repo.git"
batch = true
access = basic
[http]
sslverify = true

Commands you will run

Start up node-lfs-s3 with a command like this:

LFS_BASE_URL=http://host:port/ LFS_PORT=port LFS_STORE_TYPE=s3 LFS_AUTHENTICATOR_TYPE=none LFS_JWT_SECRET=a_secret AWS_ACCESS_KEY=aws_access_key AWS_SECRET_KEY=aws_secret_key LFS_STORE_S3_BUCKET=bucket_name LFS_S3_REGION=us-east-1 node git-lfs-server.js

Using Nodejs to record microphone input to mp3 files on Ubuntu

https://ubuntuforums.org/archive/index.php/t-224748.html was very helpful.

Install lame mp3 encoder if you don’t have it.

sudo apt-get install lame

You should already have arecord, which records audio sends it to stdout.

  1. Run the command alsamixer to see your audio inputs and tweak volumes
  2. Run the command arecord -f cd | lame – out.mp3 to record audio to an mp3 file called out.mp3 until you hit ctrl-c

Now do that with Nodejs!

OK! This will record audio until you exit the script with Ctrl+C.

const spawn = require('child_process').spawn;

// prepare 2 child processes
const recordProcess = spawn('arecord', ['-f', 'cd'])
const encodeProcess = spawn('lame', ['-', 'out.mp3'])

// pipe them
recordProcess.stdout.pipe(encodeProcess.stdin);

// get debug info if you want
/*
recordProcess.stdout.on('data', function (data) {
  console.log('Data: ' + data);
});
recordProcess.stderr.on('data', function (data) {
  console.log('Error: ' + data);
});
recordProcess.on('close', function (code) {
  console.log('arecord closed: ' + code);
});
*/

// this seems like a good idea, but might not be needed 
process.on('exit', (code) => {
  console.log(`About to exit with code: ${code}`);
  recordProcess.kill('SIGTERM');
  encodeProcess.kill('SIGTERM');
});

ffmpeg: concatenate image sequences and audio

Goal

assemble multiple image sequences and audio files into 1 video file

Assumptions/Quirks

  • ffmpeg binary is sitting in my working folder and not in my PATH, so I reference it as ./ffmpeg instead of ffmpeg
  • ffmpeg version info is:
    ffmpeg version N-82143-gbf14393-tessus Copyright (c) 2000-2016 the FFmpeg developers
    built with Apple LLVM version 8.0.0 (clang-800.0.38)
    configuration: --cc=/usr/bin/clang --prefix=/opt/ffmpeg --extra-version=tessus --enable-avisynth --enable-fontconfig --enable-gpl --enable-libass --enable-libbluray --enable-libfreetype --enable-libgsm --enable-libmodplug --enable-libmp3lame --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-libopus --enable-libschroedinger --enable-libsnappy --enable-libsoxr --enable-libspeex --enable-libtheora --enable-libvidstab --enable-libvo-amrwbenc --enable-libvorbis --enable-libvpx --enable-libwavpack --enable-libx264 --enable-libx265 --enable-libxavs --enable-libxvid --enable-libzmq --enable-version3 --disable-ffplay --disable-indev=qtkit --disable-indev=x11grab_xcb
    libavutil      55. 35.100 / 55. 35.100
    libavcodec     57. 65.100 / 57. 65.100
    libavformat    57. 57.100 / 57. 57.100
    libavdevice    57.  2.100 / 57.  2.100
    libavfilter     6. 66.100 /  6. 66.100
    libswscale      4.  3.100 /  4.  3.100
    libswresample   2.  4.100 /  2.  4.100
    libpostproc    54.  2.100 / 54.  2.100
    Hyper fast Audio and Video encoder
    usage: ffmpeg [options] [[infile options] -i infile]... {[outfile options] outfile}...
    
  • all my images in image sequences are the same dimensions and format

  • all my audio files are the same format
  • this page offers a small mp4 file to work with: http://techslides.com/sample-webm-ogg-and-mp4-video-files-for-html5
  • this is helpful https://trac.ffmpeg.org/wiki/Concatenate

Convert Video to Image Sequence:

I need images to work with, so make some!

  • images will go into the frames directory with names like frame_0001.png, frame_0002.png etc
./ffmpeg -i test7.mp4 frames/frame_%04d.png

Convert Image Sequence back to Video

https://ffmpeg.org/pipermail/ffmpeg-devel/2005-August/000523.html

  • -c:v libx264 sets the video codec
  • -crf 23 sets the quality
  • -pix_fmt yuv420p sets the pixel format to something QuickTime can read
  • -r 24 sets input and output framerates
    • input framerate is how fast the images and the sequence are meant to be played back
    • output framerate sets how much time between frames in the output video
    • fast input and slow output results in a slideshow or timelapse
    • slow input and fast output results in duplicate frames (I think)
  • -y to overwrite files without asking
./ffmpeg -r 30 -i frames/frame_%04d.png -c:v libx264 -pix_fmt yuv420p -crf 23 -r 30  -y video-from-frames.mp4

Convert Image Sequence to Video + add audio track

http://trac.ffmpeg.org/wiki/Create%20a%20video%20slideshow%20from%20images

  • -i Bonobo - Kong.mp3 specifies another input stream
  • -c:a aac converts audio to AAC format
  • -shortest limits the length of the output video to the shortest audio or video stream (in this case, the video stream is shorter)
./ffmpeg -r 24 -i frames/frame_%04d.png -i "Bonobo - Kong.mp3" -c:v libx264 -c:a aac -pix_fmt yuv420p -crf 23 -r 24 -shortest -y video-from-frames.mp4

Concatenate multiple image sequences with 1 audio track

Put this into video-input-list.txt. The images in the image sequences must all be the same size and format

file './intro/frame_%04d.png'
file './frames/frame_%04d.png'
file './outro/frame_%04d.png'

then run the command:

  • -f concat tells ffmpeg to use the concat filter
  • -safe 0 has something to do with letting ffmpeg read relative paths in the text file
./ffmpeg -r 24 -f concat -safe 0 -i video-input-list.txt -i "Bonobo - Kong.mp3" -c:v libx264 -c:a aac -pix_fmt yuv420p -crf 23 -r 24 -shortest -y video-from-frames.mp4

Concatenate multiple images sequences and concatenate multiple audio tracks

Put this into audio-input-list.txt.

file 'big_trash_tv_hit.aif.mp3'
file 'recording.mp3'
file 'vocoded-note.aif.mp3'
file 'Bonobo - Kong.mp3'

then run the command:

  • remember to specify -f concat -safe 0 again before the second input source -i audio-input-list.txt
./ffmpeg -r 24 -f concat -safe 0 -i video-input-list.txt -f concat -safe 0 -i audio-input-list.txt -c:a aac -pix_fmt yuv420p -crf 23 -r 24 -shortest -y video-from-frames.mp4

This does what I am looking for!

CSS & Spritesheet generators

I like tools that let me drag and drop a bunch of images into my browser, and generate CSS & a single image for me to integrate into my project.

Stitches is my goto tool for generating spritesheets, and I’ll keep using it for complicated sheets made of many small images.

Today, I found SpritePad which lets me manually place the sprites within the spritesheet. Sometimes I think I can do a better job at making a compact spritesheet than Stitches does, so that’s a useful feature for me. If there are enough images in the spritesheet that manually placing them is too much work, than I can go back to Stitches.

Deploying apps from circleci to Firebase hosting

The command line page of the Firebase documentation doesn’t list all the commands available to you from the firebase-tools npm package. To see them all, install the tools with npm install -g firebase-tools and execute the command firebase in your terminal.

Usage: firebase [options] [command]


  Commands:

    data:get [options]               fetch and print JSON data at the specified path
    data:push [options]  [infile]    add a new JSON object to a list of data in your Firebase
    data:set [options]  [infile]     store JSON data at the specified path via STDIN, arg, or file
    data:remove [options]            remove data from your Firebase at the specified path
    data:update [options]  [infile]  update some of the keys for the defined path in your Firebase
    deploy [options]                       deploy hosting assets and rules for the current app
    deploy:hosting [options]               deploy hosting assets for the current app
    deploy:rules [options]                 deploy security rules for the current app
    disable:hosting [options]              stop serving web traffic to your Firebase Hosting site
    help [command]                         display help information
    init [options]                         set up a Firebase app in the current directory
    list                                   list the Firebases to which you have access
    login                                  log the CLI into Firebase
    login:ci                               generate an access token for use in non-interactive environments
    logout                                 log the CLI out of Firebase
    open [options] [panel]                 open Firebase Hosting URL in browser or jump to a dashboard panel
    prefs:token                            print the currently logged in user's access token
    serve [options]                        start a local server for your static assets

  Options:

    -h, --help         output usage information
    -V, --version      output the version number
    -j, --json         output JSON instead of text, also triggers non-interactive mode
    --token     supply an auth token for this command
    --non-interactive  error out of the command instead of waiting for prompts
    --interactive      force interactive shell treatment even when not detected
    --debug            print verbose debug output and keep a debug log file

The interesting command here is:

    login:ci                               generate an access token for use in non-interactive environments

Run firebase login:ci and follow the instructions to receive an access token like awelkfjw8efwpafh8phaua9 that you can use within circleci to deploy your app.

Inside circleci

Save the access token in circleci’s project settings as an environment variable with a name like FIREBASE_DEPLOY_TOKEN. Then configure circle.yml to use the environment variable inside the deploy step like this:

deployment:
  master:
    branch: master
    commands:
      - firebase deploy --token "$FIREBASE_DEPLOY_TOKEN" --non-interactive

When a build on the master branch succeeds, circleci will use that command to log into Firebase hosting on your behalf (via the access token) and upload the files configured in your firebase.json file.

Links

When Bower install doesn’t work

If you have a bower.json file, and running bower install from the same directory appears to download packages bot not actually put them in your project directory or even create a bower_components folder, check the version number of your package inside bower.json. Sometimes a version number of 0.0.0 prevents packages from installing, but setting the version number to 0.0.1 will make it work.

Reusing an ES6 iterator? Not quite

One you’ve called iterator.next() on an array iterator enough times to make it return the last item with the property done set to true, you can’t make it go back to the first item. But you can grab a new iterator for the same array. I was surprised to find out that:

node
> var users = ['steve', 'bob', 'jill'];
> users[Symbol.iterator]() === users[Symbol.iterator]()
false

The two iterators retrieved are actually 2 different iterators. No need to shallow copy the array to get another iterator. I have a scenario where I want to loop through an array of users of a blogging service and retrieve their RSS feeds every one in a while. This will work:

var users = ['steve', 'bob', 'jill'];
var userIterator = users[Symbol.iterator]();

function oneIteration() {

  var nextItem = userIterator.next();

  if (nextItem.done) {
    userIterator = users[Symbol.iterator]();
    nextItem = userIterator.next();
  }

  // get the rss feed, or just print out the user's name for this example
  console.log(nextItem.value);

  // retrieve the next feed after some amount of time
  setTimeout(oneIteration, 5000);

}

oneIteration();

The iterator can take the place of a userIndex variable that is incremented with each RSS fetch, and reset to 0 at the end of the array. Whether this is better or worse is up to you.